import bagel.*;
import bagel.util.Colour;
import bagel.util.Point;
import bagel.util.Rectangle;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * The main class for the Shadow Donkey Kong game.
 * This class extends {@code AbstractGame} and is responsible for managing game initialization,
 * updates, rendering, and handling user input.
 *
 * It sets up the game world, initializes characters, platforms, ladders, and other game objects,
 * and runs the game loop to ensure smooth gameplay.
 */
public class ShadowDonkeyKong extends AbstractGame {

    private final Properties GAME_PROPS;
    private final Properties MESSAGE_PROPS;
    // 游戏对象
    private Mario mario;
    // 资源
    private Image marioImageLeft;
    private Image marioImageRight;
    private boolean isMainMenu = true; // 是否显示主菜单
    private boolean isGameOver = false; // 是否显示游戏结束界面
    private int finalScore; // 最终得分
    private boolean win = false; // 是否胜利
    private List<Platform> platforms; // 平台列表
    private List<Ladder> ladders;//梯子列表
    private List<Enemy> barrels;//木桶列表
    private Enemy kong;
    private Hammer hammer;
    private int maxFrames;
    private int currFrame = 0;
    private long lastTime = 0;
    private Image background;
    private int width,height;


    public ShadowDonkeyKong(Properties gameProps, Properties messageProps) {
        super(Integer.parseInt(gameProps.getProperty("window.width")),
                Integer.parseInt(gameProps.getProperty("window.height")),
                messageProps.getProperty("home.title"));
        this.width = Integer.parseInt(gameProps.getProperty("window.width"));
        Common.SCREEN_WIDTH = width;
        this.height = Integer.parseInt(gameProps.getProperty("window.height"));

        this.GAME_PROPS = gameProps;
        this.MESSAGE_PROPS = messageProps;
        
        initializeGameObjects();
    }

    private void initializeGameObjects() {
        background = new Image("res/background.png");

        // 加载倒计时的最大帧数
        maxFrames = Integer.parseInt(GAME_PROPS.getProperty("gamePlay.maxFrames"));
        currFrame = 0;
        lastTime = 0;
        win = false;

        // 加载马里奥面向左和面向右的图像
        marioImageLeft = new Image("res/mario_left.png");
        marioImageRight = new Image("res/mario_right.png");
        Image marioHammerLeft = new Image("res/mario_hammer_left.png");
        Image marioHammerRight = new Image("res/mario_hammer_right.png");

        // 初始化马里奥位置

        int marioStartX = Integer.parseInt(GAME_PROPS.getProperty("mario.start.x"));

        int marioStartY = Integer.parseInt(GAME_PROPS.getProperty("mario.start.y"));

        // 初始化平台
        platforms = new ArrayList<>();
        String[] platformConfigs = GAME_PROPS.getProperty("platforms").split(";");
        for (String config : platformConfigs) {
            String[] parts = config.split(",");
            int x = Integer.parseInt(parts[0]);
            int y = Integer.parseInt(parts[1]);
            platforms.add(new Platform(new Point(x, y), "res/platform.png"));
        }

      // 初始化梯子
        ladders = new ArrayList<>();
        int ladderCount = Integer.parseInt(GAME_PROPS.getProperty("ladder.count"));
        for (int i = 1; i <= ladderCount; i++) {
            String ladderKey = "ladder." + i;
            String[] ladderCoords = GAME_PROPS.getProperty(ladderKey).split(",");
            double x = Integer.parseInt(ladderCoords[0]);
            double y = Integer.parseInt(ladderCoords[1]);

            // 创建梯子对象
            Ladder ladder = new Ladder(new Point(x, y), "res/ladder.png");

            // 检测梯子是否与平台接触
            for (Platform platform : platforms) {
                if (platform.getBoundingBox().intersects(ladder.getBoundingBox())) {
                    // 如果接触，调整梯子的位置
                    y = platform.getPosition().y - platform.getHeight() / 2 - ladder.getHeight()/2;
                    ladder = new Ladder(new Point(x, y), "res/ladder.png");
                    break;
                }
            }

            ladders.add(ladder);
        }

         // 创建锤子
        Point hammerPos = new Point(Integer.parseInt(GAME_PROPS.getProperty("hammer.start.x")),
        Integer.parseInt(GAME_PROPS.getProperty("hammer.start.y")));
        hammer = new Hammer(hammerPos, "res/hammer.png");

        // 创建大金刚
        Point kongPos = new Point(Integer.parseInt(GAME_PROPS.getProperty("donkey.x")),
        Integer.parseInt(GAME_PROPS.getProperty("donkey.y")));
        kong = new Enemy(kongPos, "res/donkey_kong.png",new CollisionManager(platforms));

        // 初始化木桶
        barrels = new ArrayList<>();
        int barrelsCount = Integer.parseInt(GAME_PROPS.getProperty("barrel.count"));
        for (int i = 1; i <= barrelsCount; i++) {
            String ladderKey = "barrel." + i;
            String[] ladderCoords = GAME_PROPS.getProperty(ladderKey).split(",");
            double x = Integer.parseInt(ladderCoords[0]);
            double y = Integer.parseInt(ladderCoords[1]);

            // 创建木桶对象
            Enemy barrel = new Enemy(new Point(x, y), "res/barrel.png",
                                    new CollisionManager(platforms));

            barrels.add(barrel);
        }

        mario = new Mario(new Point(marioStartX, marioStartY), 
                                marioImageLeft, marioImageRight, 
                                marioHammerLeft,marioHammerRight,
                                new CollisionManager(platforms,ladders,barrels,kong,hammer));
    }

    /**
     * Render the relevant screen based on the keyboard input given by the user and the status of the gameplay.
     * @param input The current mouse/keyboard input.
     */
    @Override
    protected void update(Input input) {
        long currTime = System.currentTimeMillis(); // 记录当前帧的开始时间
        long deltaTime = currTime-lastTime;
        if( deltaTime < 1000/Common.FPS){
             //降低帧率
            try {
                deltaTime = 1000 / Common.FPS - deltaTime;
                Thread.sleep(deltaTime); // 1000 毫秒 / 帧率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        lastTime = System.currentTimeMillis();
        background.draw(width/2, height/2);
        if (input.wasPressed(Keys.ESCAPE)) {
            Window.close();
        }
        if (isMainMenu) {
            renderMainMenu();
            // 检测是否按下回车键
            if (input.wasPressed(Keys.ENTER)) {
                isMainMenu = false; // 切换到游戏状态
            }
        }else if (isGameOver) {
            // 渲染游戏结束界面
            renderGameOverScreen();
    
            // 检测是否按下空格键
            if (input.wasPressed(Keys.SPACE)) {
                isGameOver = false; // 返回主菜单
                isMainMenu = true; // 显示主菜单
                initializeGameObjects();
            }
        }  else {
            // 更新马里奥的位置
            mario.update(input);
            kong.update();
            for(Enemy e:barrels){
                e.update();
            }

            // 渲染平台
            for (Platform platform : platforms) {
                platform.render();
            }
            //渲染梯子
            for (Ladder ladder : ladders) {
                ladder.render();
            }
            for(Enemy e:barrels){
                e.render();
            }
            //渲染锤子
            if(!mario.hasHammer()){
                hammer.render();
            }
            
            
            kong.render();
            // 调用 render 方法
            mario.render();

            //显示分数和剩余时间
            renderScoreAndTime();
            currFrame++;
            

            // 检测游戏结束条件
            if (!mario.isAlive() || mario.getWin() || currFrame>=maxFrames) {
                isGameOver = true; // 切换到游戏结束状态
                win = mario.getWin();
                finalScore = mario.getScore()/* 计算最终得分 */;
                if(win){
                    finalScore+=Common.TIME_LEFT_BONUS_RATE*(maxFrames - currFrame)/Common.FPS;
                }
            }
        }

       
    }
    private void renderScoreAndTime(){
        int scoreFontSize=0,scoreX=0,scoreY=0;
        Font scoreFont=null;

        // 加载分数显示的字体大小和位置
        scoreFontSize = Integer.parseInt(GAME_PROPS.getProperty("gamePlay.score.fontSize"));
        scoreX = Integer.parseInt(GAME_PROPS.getProperty("gamePlay.score.x"));
        scoreY = Integer.parseInt(GAME_PROPS.getProperty("gamePlay.score.y"));

        // 加载字体文件
        String fontPath = GAME_PROPS.getProperty("font");
        scoreFont = new Font(fontPath, scoreFontSize);

         // 渲染分数
        scoreFont.drawString("Score " + mario.getScore(), scoreX, scoreY);
        
        //渲染剩余时间
        scoreFont.drawString("Left Time "+(maxFrames-currFrame)/Common.FPS, scoreX, scoreY+30);
    }
    private void renderMainMenu() {
        // 渲染标题
        Font titleFont = new Font("res/FSO8BITR.TTF", Integer.parseInt(GAME_PROPS.getProperty("home.title.fontSize")));
        String titleText = GAME_PROPS.getProperty("home.title");
        double titleWidth = titleFont.getWidth(titleText);
        double titleX = (Window.getWidth() - titleWidth) / 2; // 动态计算居中位置
        double titleY = Integer.parseInt(GAME_PROPS.getProperty("home.title.y"));
        titleFont.drawString(titleText, titleX, titleY);
    
        // 渲染提示信息
        Font promptFont = new Font("res/FSO8BITR.TTF", Integer.parseInt(GAME_PROPS.getProperty("home.prompt.fontSize")));
        String promptText = GAME_PROPS.getProperty("home.prompt");
        double promptWidth = promptFont.getWidth(promptText);
        double promptX = (Window.getWidth() - promptWidth) / 2; // 动态计算居中位置
        double promptY = Integer.parseInt(GAME_PROPS.getProperty("home.prompt.y"));
        promptFont.drawString(promptText, promptX, promptY);
    }

    private void renderGameOverScreen() {
        // 渲染游戏结束消息
        Font gameOverFont = new Font("res/FSO8BITR.TTF", Integer.parseInt(GAME_PROPS.getProperty("gameEnd.status.fontSize")));
        String gameOverMessage = win ? MESSAGE_PROPS.getProperty("gameEnd.won") : MESSAGE_PROPS.getProperty("gameEnd.lost");
        double gameOverX = (Window.getWidth() - gameOverFont.getWidth(gameOverMessage)) / 2;
        double gameOverY = Integer.parseInt(GAME_PROPS.getProperty("gameEnd.status.y"));
        gameOverFont.drawString(gameOverMessage, gameOverX, gameOverY);
    
        // 渲染最终得分
        Font scoreFont = new Font("res/FSO8BITR.TTF", Integer.parseInt(GAME_PROPS.getProperty("gameEnd.scores.fontSize")));
        String scoreText = MESSAGE_PROPS.getProperty("gameEnd.score") + " " + finalScore;
        double scoreX = (Window.getWidth() - scoreFont.getWidth(scoreText)) / 2;
        double scoreY = Integer.parseInt(GAME_PROPS.getProperty("gameEnd.scores.y"));
        scoreFont.drawString(scoreText, scoreX, scoreY);
    
        // 渲染提示信息
        String continueText = MESSAGE_PROPS.getProperty("gameEnd.continue");
        double continueX = (Window.getWidth() - scoreFont.getWidth(continueText)) / 2;
        double continueY = Window.getHeight() - 100;
        scoreFont.drawString(continueText, continueX, continueY);
    }

    /**
     * The main entry point of the Shadow Donkey Kong game.
     *
     * This method loads the game properties and message files, initializes the game,
     * and starts the game loop.
     *
     * @param args Command-line arguments (not used in this game).
     */
    public static void main(String[] args) {
        Properties gameProps = IOUtils.readPropertiesFile("res/app.properties");
        Properties messageProps = IOUtils.readPropertiesFile("res/message_en.properties");
        ShadowDonkeyKong game = new ShadowDonkeyKong(gameProps, messageProps);
        game.run();
        
    }


}
